_counts = {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five',
           6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten',
           11: 'eleven', 12: 'twelve'}

def format_count(count):
    if count in _counts:
        return _counts[count]
    if count < 1000:
        return str(count)
    elif count < 1000000:
        return '%d,%d' % (count // 1000, count % 1000)
    else:
        return '%d,%d,%d' % (count // 1000000, (count % 1000000) // 1000,
                             count % 1000)

# Prefix rules for indefinite articles.
_indefinite_articles = {'a': 'an',
                        'e': 'an',
                        'i': 'an',
                        'o': 'an',
                        'u': 'an',
                        'uni': 'a'}

def indefinite_article(noun):
    prefix = noun.split(' ', 1)[0]
    while prefix:
        article = _indefinite_articles.get(prefix)
        if article is not None:
            return article
        prefix = prefix[:-1]
    return 'a'

def add_indefinite_article(phrase):
    return '%s %s' % (indefinite_article(phrase), phrase)

def to_definite_article(phrase):
    for prefix in ('a ', 'an '):
        if phrase.startswith(prefix):
            return phrase.replace(prefix, 'the ', 1)
    return phrase

def to_count_article(count, phrase):
    for prefix in ('a ', 'an ', 'the '):
        if phrase.startswith(prefix):
            return phrase.replace(prefix, format_count(count) + ' ', 1)
    return phrase

_material_adjectives = {'adamant': 'adamantine',
                        'dragon_scales': 'dragon scale',
                        'gold': 'golden',
                        'hydra_scales': 'hydra scale',
                        'lindworm_scales': 'lindworm scale',
                        'wood': 'wooden',
                        'wyvern_scales': 'wyvern scale'}

def material_adjective(material):
    return _material_adjectives.get(material, material.replace('_', ' '))

def definite_description(thing):
    return to_definite_article(str(thing))

# Suffix rules for converting singular verbs to plural form.
_plural_verbs = {'has': 'have',
                 'hes': 'h',
                 'is': 'are',
                 'oes': 'o',
                 's': ''}

# Suffix rules for converting singular nouns to plural form.
_plural_nouns = {'': 's',
                 'f': 'ves',
                 'fe': 'ves',
                 'human': 'humans',
                 'if': 'ifs',
                 'man': 'men',
                 's': 'ses'}

def plural_verb(verb):
    """Convert a verb phrase in singular form to plural form.

    Examples:

      takes -> take
      is not -> are not
      cannot leave -> cannot leave
    """

    words = verb.split(' ', 1)
    words[0] = plural_word(words[0], _plural_verbs)
    return ' '.join(words)

def plural_noun(noun):
    """Convert a noun phrase in singular form to plural form.

    Examples:

      dwarf -> dwarves
      red apple -> red apples
      bag of holding -> bags of holding
    """

    if ' of ' in noun:
        noun, suffix = noun.split(' of ', 1)
        suffix = ' of ' + suffix
    else:
        suffix = None
    words = noun.split(' ')
    words[-1] = plural_word(words[-1], _plural_nouns)
    noun = ' '.join(words)
    if suffix is not None:
        noun += suffix
    return noun

def plural_word(word, rules):
    for i in xrange(len(word) + 1):
        sub = rules.get(word[i:])
        if sub is not None:
            return word[:i] + sub
    return word

def render_default_message(subj, verb, obj = None, prep = None, ind = None,
                           observer = None, definite = None):
    def describe(thing):
        if thing is observer:
            return 'you'
        elif definite and definite(thing):
            return definite_description(thing)
        else:
            return str(thing)
    message = describe(subj) + ' '
    if subj is observer or subj.count > 1:
        verb = plural_verb(verb)
    message += verb
    if obj:
        message += ' ' + describe(obj)
    if prep:
        message += ' ' + prep
    if ind:
        message += ' ' + describe(ind)
    return message[0].capitalize() + message[1:] + '.'

def indefinite_article_test():
    assert indefinite_article('apple') == 'an'
    assert indefinite_article('axe') == 'an'
    assert indefinite_article('dwarf') == 'a'
    assert indefinite_article('elf') == 'an'
    assert indefinite_article('human') == 'a'
    assert indefinite_article('orc') == 'an'
    assert indefinite_article('sword') == 'a'
    assert indefinite_article('unicorn') == 'a'

    assert indefinite_article('blessed sword') == 'a'
    assert indefinite_article('yellow mushroom') == 'a'

def plural_verb_test():
    assert plural_verb('can') == 'can'
    assert plural_verb('cannot') == 'cannot'
    assert plural_verb('closes') == 'close'
    assert plural_verb('dies') == 'die'
    assert plural_verb('drinks') == 'drink'
    assert plural_verb('drops') == 'drop'
    assert plural_verb('eats') == 'eat'
    assert plural_verb('finds') == 'find'
    assert plural_verb('goes') == 'go'
    assert plural_verb('has') == 'have'
    assert plural_verb('hits') == 'hit'
    assert plural_verb('is') == 'are'
    assert plural_verb('locks') == 'lock'
    assert plural_verb('looks') == 'look'
    assert plural_verb('kicks') == 'kick'
    assert plural_verb('makes') == 'make'
    assert plural_verb('opens') == 'open'
    assert plural_verb('pushes') == 'push'
    assert plural_verb('removes') == 'remove'
    assert plural_verb('returns') == 'return'
    assert plural_verb('searches') == 'search'
    assert plural_verb('shatters') == 'shatter'
    assert plural_verb('splinters') == 'splinter'
    assert plural_verb('takes') == 'take'
    assert plural_verb('throws') == 'throw'
    assert plural_verb('unlocks') == 'unlock'
    assert plural_verb('wears') == 'wear'
    assert plural_verb('wields') == 'wield'

def plural_noun_test():
    assert plural_noun('apple') == 'apples'
    assert plural_noun('axe') == 'axes'
    assert plural_noun('armor') == 'armors'
    assert plural_noun('boot') == 'boots'
    assert plural_noun('cloak') == 'cloaks'
    assert plural_noun('coif') == 'coifs'
    assert plural_noun('corpse') == 'corpses'
    assert plural_noun('dagger') == 'daggers'
    assert plural_noun('dwarf') == 'dwarves'
    assert plural_noun('elf') == 'elves'
    assert plural_noun('gauntlet') == 'gauntlets'
    assert plural_noun('glove') == 'gloves'
    assert plural_noun('hammer') == 'hammers'
    assert plural_noun('helm') == 'helms'
    assert plural_noun('human') == 'humans'
    assert plural_noun('knife') == 'knives'
    assert plural_noun('man') == 'men'
    assert plural_noun('mushroom') == 'mushrooms'
    assert plural_noun('shield') == 'shields'
    assert plural_noun('shirt') == 'shirts'
    assert plural_noun('shoe') == 'shoes'
    assert plural_noun('spear') == 'spears'
    assert plural_noun('sword') == 'swords'
    assert plural_noun('troll') == 'trolls'
    assert plural_noun('woman') == 'women'

    assert plural_noun('bag of holding') == 'bags of holding'
    assert plural_noun('troll corpse') == 'troll corpses'

def test():
    indefinite_article_test()
    plural_verb_test()
    plural_noun_test()

if __name__ == '__main__':
    test()
